#include "common/common.h"
#include "Core/TCFixedString.h"
#include "string/stringoutput.h"
#include "Core/TCSimpleDynamicSortedArray.h"
#include "testlibpilo.h"

using namespace PILO::Core::Containers;
using namespace PILO::Core::String;
using namespace PILO::Core::Memory;

static INT32 g_id = 0;

static INT32 case_TCSimpleDynamicSortedArray_Operator_Equal(void* param);
static INT32 case_TCSimpleDynamicSortedArray_CopyConstructor(void* param);
static INT32 case_TCSimpleDynamicSortedArray_constInternalData(void* param);
static INT32 case_TCSimpleDynamicSortedArray_constAt(void* param);
static INT32 case_TCSimpleDynamicSortedArray_takeLast(void* param);
static INT32 case_TCSimpleDynamicSortedArray_takeFirst(void* param);
static INT32 case_TCSimpleDynamicSortedArray_indexOf(void* param);
static INT32 case_TCSimpleDynamicSortedArray_insertUnique(void* param);
static INT32 case_TCSimpleDynamicSortedArray_removeAt(void* param);
static INT32 case_TCSimpleDynamicSortedArray_removeOne(void* param);
static INT32 case_TCSimpleDynamicSortedArray_removeAll(void* param);
static INT32 case_TCSimpleDynamicSortedArray_attach_detach(void* param);


static case_testing_t g_cases_TCSimpleDynamicSortedArray[] = {
    {1,  "TCSimpleDynamicSortedArray::operator=             ", 0,  case_TCSimpleDynamicSortedArray_Operator_Equal,           -1},
    {2,  "TCSimpleDynamicSortedArray_CopyConstructor        ", 0,  case_TCSimpleDynamicSortedArray_CopyConstructor,          -1},
    {3,  "TCSimpleDynamicSortedArray::internalData          ", 0,  case_TCSimpleDynamicSortedArray_constInternalData,        -1},
    {4,  "TCSimpleDynamicSortedArray::at                    ", 0,  case_TCSimpleDynamicSortedArray_constAt,                  -1},
    {5,  "TCSimpleDynamicSortedArray::takeLast              ", 0,  case_TCSimpleDynamicSortedArray_takeLast,                 -1},
    {6,  "TCSimpleDynamicSortedArray::takeFirst             ", 0,  case_TCSimpleDynamicSortedArray_takeFirst,                -1},
    {7,  "TCSimpleDynamicSortedArray::indexOf               ", 0,  case_TCSimpleDynamicSortedArray_indexOf,                  -1},
    {8,  "TCSimpleDynamicSortedArray::insertUnique          ", 0,  case_TCSimpleDynamicSortedArray_insertUnique,             -1},
    {9,  "TCSimpleDynamicSortedArray::removeAt              ", 0,  case_TCSimpleDynamicSortedArray_removeAt,                 -1},
    {10, "TCSimpleDynamicSortedArray::removeOne             ", 0,  case_TCSimpleDynamicSortedArray_removeOne,                -1},
    {11, "TCSimpleDynamicSortedArray::removeAll             ", 0,  case_TCSimpleDynamicSortedArray_removeAll,                -1},
    {12, "TCSimpleDynamicSortedArray::_attach_detach        ", 0,  case_TCSimpleDynamicSortedArray_attach_detach,            -1},
};

INT32 test_TCSimpleDynamicSortedArray_Functional(INT32 id, BOOL breakOnErrorOccured)
{
    g_id = id;

    FormatOutputToConsole("Testing Part_%d <pilotsimpledynamicsortedarray.h>\n", id);
    int i=0;
    for (i=0; i<MCF_COUNT_OF(g_cases_TCSimpleDynamicSortedArray); i++) {
        case_testing_t * caseParam = &g_cases_TCSimpleDynamicSortedArray[i];
        ASSERT(caseParam != NULL);
        FormatOutputToConsole(" #[%03d.%03d]: Testing %s",g_id, caseParam->ct_id, caseParam->ct_decription);

        caseParam->ct_result = caseParam->ct_function(static_cast<case_testing_t *>(caseParam));
        if (caseParam->ct_result == 0) { //ok
            FormatOutputToConsole("[PASSED]\n");
        } else {
            FormatOutputToConsole("[FAILED:%d]\n",caseParam->ct_result);
            if (breakOnErrorOccured) {
                ASSERT(FALSE);
            }
        }
    }


    FormatOutputToConsole("Result of Part_%d <pilotsimpledynamicsortedarray.h> total  %d, failed %d\n\n",id, MCF_COUNT_OF(g_cases_TCSimpleDynamicSortedArray), failedOFCases(g_cases_TCSimpleDynamicSortedArray,MCF_COUNT_OF(g_cases_TCSimpleDynamicSortedArray)));
    return 0;
}

static INT32 case_TCSimpleDynamicSortedArray_Operator_Equal(void* )
{
    TestElement element;

    TCSimpleDynamicSortedArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicSortedArray(arraySrc, 100, "EQL");
    if (arraySrc.size() != 100) {
        return -1;
    }
    //TDebugOutputArray(arraySrc);

    TCSimpleDynamicSortedArray<TestElement, 1, 5> arrayDst;
    arrayDst = arraySrc;
    //TDebugOutputArray(arrayDst);

    for (int i=0; i<100; i++) {
        element.set(i, "EQL");
        if (arrayDst[i] != element) {
            return -1;
        }
    }

    //TDebugOutputArray(arraySrc);

    return 0;
}

static INT32 case_TCSimpleDynamicSortedArray_CopyConstructor(void* )
{
    TestElement element;

    TCSimpleDynamicSortedArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicSortedArray(arraySrc, 100, "FOX");
    //check this array
    if (arraySrc.size() != 100) {
        return -1;
    }

    TCSimpleDynamicSortedArray<TestElement, 1, 5> arrayDest(arraySrc);
    if (arrayDest.size() != 100) {
        return -1;
    }
    for (int i=0; i<100; i++) {
        element.set(i, "FOX");
        if (arrayDest[i] != element) {
            return -1;
        }
    }

    return 0;
}

INT32 case_TCSimpleDynamicSortedArray_constInternalData(void *)
{
    TCSimpleDynamicSortedArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicSortedArray(arraySrc, 100, "DAT");
   // TDebugOutputArray(arraySrc);

    char buf[30];
    char compareBuffer[sizeof(TestElement)*100];
    memset(compareBuffer,0x00, sizeof(TestElement)*100);
    size_t index = 0;
    // fill this array
    for (int i=0; i<100; i++) {
        memcpy(compareBuffer+index, &i, sizeof(i));
        index += sizeof(i);

        size_t checkLen = FormatOutputToString(buf, MCF_COUNT_OF(buf), "DAT @ %010d", i);
        if (checkLen != StringLength(buf)) {
            return -1;
        }
        memcpy(compareBuffer+index, buf, checkLen);
        index += 32;
    }

    index = 0;
    for (int j=0; j<100; j++) {
        const TestElement * ep = arraySrc.constInternalData()+j;
        int cmpID;
        memcpy(&cmpID, compareBuffer + index, sizeof(cmpID));
        if (ep->id() != cmpID) {
            return (j*100+1);
        }

        if (   0 != StringCompare( ep->data(), compareBuffer+index+sizeof(int)   )  ) {
            return (j*100+2);
        }

        index += sizeof(TestElement);
    }

    return 0;
}

static INT32 case_TCSimpleDynamicSortedArray_constAt(void* )
{
    TCSimpleDynamicSortedArray<TestElement, 1, 5> arraySrc;
    TMakeSampleDynamicSortedArray(arraySrc, 100, "PeT");

    const TestElement&  elementValid = arraySrc.at(99);
    TestElement ele1;
    ele1.set(99,"PeT");
    if (elementValid != ele1) {
        return -1;
    }

    if (arraySrc.exist(100) != MC_NULLPTR_OF_(TestElement*)) {
        return -2;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicSortedArray_takeLast(void* )
{
    TCSimpleDynamicSortedArray<TestElement, 1, 7> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 8, "TKL");

    TestElement element = arrayTest.takeLast();
    TestElement ele1(7, "TKL @ 0000000007");
    if ((element != ele1) || (arrayTest.size() != 7) || (arrayTest.capacity() != 8)) {
        return -1;
    }

    return 0;
}
static INT32 case_TCSimpleDynamicSortedArray_takeFirst(void* )
{
    TCSimpleDynamicSortedArray<TestElement, 1, 100> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 100, "TKF");
    //TDebugOutputArray(arrayTest);

    INT32 i=0;
    while(! arrayTest.isEmpty()) {

        TestElement cmpElement;
        cmpElement.set(i, "TKF");

        TestElement firstElement = arrayTest.takeFirst();

        if (firstElement != cmpElement) {
            return -2;
        }
        i++;
    }

    return 0;
}

static INT32 case_TCSimpleDynamicSortedArray_indexOf(void* )
{
    TCSimpleDynamicSortedArray<TestElement, 1, 100> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 100, "IDO");

    TestElement cmpElement;
    cmpElement.set(57, "IDO");

    size_t ind = arrayTest.indexOf(cmpElement);
    if (ind != 57) {
        return -1;
    }
    TestElement cmpElementE;
    cmpElementE.set(57, "IDN");
    ind = arrayTest.indexOf(cmpElementE);
    if (ind != 57) {
        return -2;
    }
    //test accurate search
    ind = arrayTest.indexOf(cmpElementE,TRUE);
    if (ind != MC_INVALID_SIZE) {
        return -3;
    }
    
    TestElement cmpElementD;
    cmpElementD.set(57,"IDD");
    arrayTest.insert(cmpElementD);

    //TDebugOutputArray(arrayTest);

    ind = arrayTest.indexOf(cmpElement,TRUE);
    if (ind == MC_INVALID_SIZE) {
        return -4;
    }

    //test accurate search - failed
    ind = arrayTest.indexOf(cmpElementE,TRUE);
    if (ind != MC_INVALID_SIZE) {
        return -5;
    }

        
    return 0;
}

INT32 case_TCSimpleDynamicSortedArray_insertUnique( void*  )
{
    TCSimpleDynamicSortedArray<TestElement, 1, 100> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 10, "INU");

    TestElement element;
    element.set(10, "INU");

    size_t pos = arrayTest.insertUnique(element, FALSE);
    if (pos != 10) {
        return -1;
    }

    pos = arrayTest.insertUnique(element, FALSE);
    if (pos != MC_INVALID_SIZE) {
        return -2;
    }

    element.set(8, "INX");
    pos = arrayTest.insertUnique(element, TRUE);
    if (pos != 8) {
        return -3;
    }

    //TDebugOutputArray(arrayTest);
    return 0;
}

INT32 case_TCSimpleDynamicSortedArray_removeAt( void*  )
{
    TCSimpleDynamicSortedArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 10, "REM");

    arrayTest.removeAt(9);
    arrayTest.removeAt(7);
    arrayTest.removeAt(0);

    if (arrayTest.count() != 7) {
        return -1;
    }
    TestElement ele1;
    ele1.set(1,"REM");
    if (arrayTest[0] != ele1) {
        return -2;
    }

    for(int i=0;i<7;i++) {
        arrayTest.removeAt(0);
    }
    if (arrayTest.count() != 0) {
        return -3;
    }

    return 0;

}

INT32 case_TCSimpleDynamicSortedArray_removeOne( void*  )
{
    TCSimpleDynamicSortedArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 10, "RM1");

    TestElement ele1;
    ele1.set(1,"RM1");

    //remove one: match with operator <
    BOOL founded = arrayTest.removeOne(ele1);
    if (! founded) {
        return -1;
    }

    founded = arrayTest.removeOne(ele1);
    if (founded) {
        return -2;
    }

    //remove all: accurate match. match all content, use element's equal operator
    arrayTest.clear();
    TMakeSampleDynamicSortedArray(arrayTest, 10, "RM1");
    ele1.set(3, "RM0");
    founded = arrayTest.removeOne(ele1, TRUE);
    if (founded) {
        return -3;
    }

    founded = arrayTest.removeOne(ele1);
    if (! founded) {
        return -4;
    }

    return 0;
}

INT32 case_TCSimpleDynamicSortedArray_removeAll( void*  )
{
    TCSimpleDynamicSortedArray<TestElement, 10, 1> arrayTest;
    TMakeSampleDynamicSortedArray(arrayTest, 10, "RMA");

    TestElement ele1;
    ele1.set(7,"RM1");

    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);

    //remove all: use < compare only
    size_t removeCount = arrayTest.removeAll(ele1);
    if (removeCount != 4) {
        return -1;
    }

    //remove all: accurate match. match all content, use element's equal operator
    arrayTest.clear();
    TMakeSampleDynamicSortedArray(arrayTest, 10, "RMA");
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    //TDebugOutputArray(arrayTest);
    removeCount = arrayTest.removeAll(ele1, TRUE);
    if (removeCount != 3) {
        return -2;
    }

    //remove all: accurate match , failed cases
    arrayTest.clear();
    TMakeSampleDynamicSortedArray(arrayTest, 10, "RMA");
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    ele1.set(11, "RMA");
    removeCount = arrayTest.removeAll(ele1, FALSE);
    if (removeCount != 0) {
        return -3;
    }

    //remove all: test limits
    arrayTest.clear();
    TMakeSampleDynamicSortedArray(arrayTest, 10, "RMA");
    ele1.set(7,"RMA");
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    arrayTest.insert(ele1);
    removeCount = arrayTest.removeAll(ele1, TRUE,2);
    if (removeCount != 2) {
        return -4;
    }




    return 0;
}

INT32 case_TCSimpleDynamicSortedArray_attach_detach( void* )
{
    TestElement arrayData[100];
    arrayData[0].set(0,"ATT");
    TCSimpleDynamicSortedArray<TestElement, 10, 1> arrayTest;
    arrayTest.attach(arrayData,100,1);

    for (int index=1; index<100; index++) {
        TestElement ele1;
        ele1.set(index, "ATT");
        arrayTest.insert(ele1);
    }

    if (arrayTest.count() != 100) {
        return -1;
    }

    for (int i=0; i<100; i++) {
        TestElement ele1;
        ele1.set(i,"ATT");

        if (arrayTest.at(i) != ele1) {
            return -2;
        }
    }

    arrayTest.detach();

    if (arrayTest.count()!=0) {
        return -3;
    }
    if (arrayTest.capacity() != 0) {
        return -4;
    }
    if (!arrayTest.isMemoryOwner()) {
        return -5;
    }
    if (arrayTest.constInternalData() != MC_NULLPTR_OF_(TestElement*)) {
        return -6;
    }
    return 0;
}
